package com.allwees.bs.module.base.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.allwees.bs.core.modelbase.bo.Bo;
import com.allwees.bs.core.modelbase.req.BoCrudReq;
import com.allwees.bs.core.modelbase.req.Queryable;
import com.allwees.bs.module.base.service.BoService;
import com.allwees.core.common.constant.EStatus;
import com.allwees.core.common.util.reflect.ReflectionUtils;
import com.allwees.core.dao.DbException;
import com.allwees.core.dao.mybatis.dao.BaseDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author mhn
 * @since 2019-10-14 16:55
 */
@Slf4j
public abstract class BoServiceImpl<D extends BaseDao<B>, B extends Bo> extends ServiceImpl<D, B> implements BoService<B> {
	private Class<B> boClass;

	protected BoServiceImpl() {
		super();

		if(!this.getClass().equals(BoServiceImpl.class)) {
			boClass = ReflectionUtils.getGenricParameterType(this.getClass(), BoServiceImpl.class, 1);
		}
	}

	@Override
	public B findByUuid(String uuid) {
        return baseMapper.findByUuid(uuid);
	}

	@Override
	public B checkByUuid(String uuid) {
		B bo = findByUuid(uuid);
		Assert.notNull(bo, "data[uuid: " + uuid + "] is not exist");
		return bo;
	}

	@Override
	public List<B> findByUuids(Set<String> uuids) {
		return baseMapper.findByUuids(uuids);
	}

	@Override
	public List<B> findByUuids(String... uuids) {
        return findByUuids(new HashSet<>(Arrays.asList(uuids)));
	}

	@Override
	public List<B> findListByFieldValues(String fieldName, Object... values) {
		return baseMapper.findListByFieldValues(fieldName, new HashSet<>(Arrays.asList(values)));
	}

	@Override
	public B findOneByField(String fieldName, String value) {
		return baseMapper.findOneByField(fieldName, value);
	}

	@Override
	public B findUniqueByField(String fieldName, String value) {
		return baseMapper.findUniqueByField(fieldName, value);
	}

	@Override
	public <P extends Queryable<B>> int findCount(P req) {
		return baseMapper.selectCount(req.toQueryWrapper());
	}

	@Override
	public <P extends Queryable<B>> B findOne(P req) {
		return baseMapper.selectOne(req.toQueryWrapper());
	}

	@Override
	public <P extends Queryable<B>> B findUnique(P req) {
		int count = findCount(req);
		if(count == 0) {
			return null;
		} else if(count > 1) {
			String msg = String.format("记录不唯一: 条件[%s]存在 %d 条记录", req.toQueryWrapper().toString(), count);
			throw new DbException(msg);
		}
		return findOne(req);
	}

	@Override
	public <P extends Queryable<B>> List<B> findList(P req) {
		return baseMapper.selectList(req.toQueryWrapper());
	}

	@Override
	public <P extends Queryable<B>> IPage<B> findPage(Page<B> page, P req) {
		return baseMapper.selectPage(page, req.toQueryWrapper());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean create(BoCrudReq<B> req) {
		return create(req.toEntity());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean create(B bo) {
		return baseMapper.create(bo);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean updateByUuid(BoCrudReq<B> req) {
		return updateByUuid(req.toEntity());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean updateByUuid(B bo) {
        return baseMapper.updateByUuid(bo, bo.getUuid()) > 0;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public int updateStatusByUuids(EStatus status, String... uuids) {
        return updateStatusByUuids(status, Arrays.asList(uuids));
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public int updateStatusByUuids(EStatus status, Collection<String> uuids) {
		try {
			B bo = boClass.newInstance();
			bo.setStatus(status.value());
	        return baseMapper.updateByUuids(bo, new HashSet<>(uuids));
		} catch(InstantiationException | IllegalAccessException e) {
			throw new DbException();
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean deleteByUuid(String uuid) {
		return baseMapper.deleteByUuid(uuid);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public int deleteByUuids(String... uuids) {
		return baseMapper.deleteByUuids(new HashSet<>(Arrays.asList(uuids)));
	}
}
